package com.homedo.microservice.open.service.gateway.alert.task;


import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.homedo.common.bean.data.ResponseData;
import com.homedo.common.bean.data.enums.ResponseEnum;
import com.homedo.common.bean.vo.Order;
import com.homedo.common.bean.vo.Pagination;
import com.homedo.common.util.Detect;
import com.homedo.common.util.HttpUtility;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.enums.foralertnotice.StatusEnum4AlertNotice;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.enums.forroute.StatusEnum4Route;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.enums.forrouteserviceurl.StatusEnum4RouteServiceUrl;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.*;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteServiceEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteServiceUrlEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.query.RouteQuery;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.query.RouteServiceUrlQuery;
import com.homedo.microservice.open.service.gateway.alert.gateway.persistence.dao.*;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.HealthCheckingErrorStatisticsService;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.RouteService;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.RouteServiceUrlService;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 不健康的后端服务器检测--如已健康就恢复服务并发送恢复通知
 */
@Component
public class IllHealthServerDetectTask {
    @Autowired
    private RouteServiceUrlService routeServiceUrlService;
    @Autowired
    private HealthCheckingErrorStatisticsService healthCheckingErrorStatisticsService;
    @Autowired
    private RouteService routeService;
    @Autowired
    private AlertingDao alertingDao;
    @Autowired
    private AlertNoticeDao alertNoticeDao;
    @Autowired
    private AlertUserRouteServiceDao alertUserRouteServiceDao;
    @Autowired
    private AlertUserDao alertUserDao;
    @Autowired
    private HealthCheckingErrorStatisticsDao healthCheckingErrorStatisticsDao;

    private static final Logger LOGGER = LoggerFactory.getLogger(IllHealthServerDetectTask.class);

    //检测应用
    private DynamicStringProperty applicationNames = DynamicPropertyFactory.getInstance().getStringProperty("alert.applicationNames", "");
    private DynamicStringProperty env = DynamicPropertyFactory.getInstance().getStringProperty("alert.env", "");
    private DynamicStringProperty smsAddr = DynamicPropertyFactory.getInstance().getStringProperty("alert.smsAddr", "http://micro-innerapi.homedo.com/message-service/sms/send");
    private DynamicStringProperty emailAddr = DynamicPropertyFactory.getInstance().getStringProperty("alert.emailAddr", "http://micro-innerapi.homedo.com/message-service/email/send");


    @Scheduled(cron = "0/6 * * * * ?")
    public void task() {

        this.doSchedule();

    }

    private void doSchedule() {
        if (!Detect.notEmpty(applicationNames.get())) {
            return;
        }

        String[] applicationNameParts = applicationNames.get().split(",");
        for (String applicationNamePart : applicationNameParts) {
            this.dealServiceGateway(applicationNamePart.trim());
        }

    }

    private void dealServiceGateway(String applicationName) {
        Pagination<RouteEnhanced> routeEnhancedPagination = new Pagination<>(1, Integer.MAX_VALUE, false);
        routeEnhancedPagination.addOrder(new Order(Route.COLUMN_CREATE_TIME, Order.ORDER_DESC), Route.class);
        RouteQuery routeQuery = new RouteQuery();
        routeQuery.setStatuses(Lists.newArrayList(StatusEnum4Route.EFFECTIVE.getCode()));
        routeQuery.setApplicationNames(Lists.newArrayList(applicationName));

        routeEnhancedPagination = routeService.getPagination(routeQuery, routeEnhancedPagination, null);
        if (!Detect.notEmpty(routeEnhancedPagination.getItems())) {
            return;
        }

        List<String> serviceIds = routeEnhancedPagination.getItems().stream().map(RouteEnhanced::getRouteServiceEnhanced)
                .collect(Collectors.toList()).stream().map(RouteServiceEnhanced::getId).collect(Collectors.toList());

        Pagination<RouteServiceUrlEnhanced> pagination = new Pagination(1, Integer.MAX_VALUE, false);
        pagination.addOrder(new Order(RouteServiceUrl.COLUMN_CREATE_TIME, Order.ORDER_DESC), RouteServiceUrl.class);

        RouteServiceUrlQuery routeServiceUrlQuery = new RouteServiceUrlQuery();
        routeServiceUrlQuery.setStatuses(Lists.newArrayList(StatusEnum4RouteServiceUrl.ILL_HEALTH.getCode()));
        routeServiceUrlQuery.setServiceIds(serviceIds);

        pagination = routeServiceUrlService.getPagination(routeServiceUrlQuery, pagination, null);
        if (!Detect.notEmpty(pagination.getItems())) {
            return;
        }

        pagination.setItems(routeServiceUrlService.appendEnhancedRouteService(pagination.getItems(), null));

        pagination.getItems().forEach(e -> {
            if (e.getRouteServiceEnhanced() != null && Detect.notEmpty(e.getRouteServiceEnhanced().getHealthUrl())) {
                String checkUrl = e.getUrl() + e.getRouteServiceEnhanced().getHealthUrl();
                if (this.checkGet(checkUrl)) {
                    this.dealCheckSucc(e, applicationName);
                }
            }
        });

    }

    private void dealCheckSucc(RouteServiceUrlEnhanced routeServiceUrlEnhanced, String applicationName) {
        RouteServiceUrl updateRecord = new RouteServiceUrl();
        updateRecord.setId(routeServiceUrlEnhanced.getId());
        updateRecord.setUpdateTime(new Date());
        updateRecord.setStatus((int) StatusEnum4RouteServiceUrl.EFFECTIVE.getCode());

        routeServiceUrlService.updateByPrimaryKeySelective(updateRecord, null);

        this.dealAlert(routeServiceUrlEnhanced, applicationName);
    }

    private void dealAlert(RouteServiceUrlEnhanced routeServiceUrlEnhanced, String applicationName) {
        Alerting alerting = new Alerting();
        alerting.setApplicationName(routeServiceUrlEnhanced.getRouteServiceEnhanced().getApplicationName());
        alerting.setServiceId(routeServiceUrlEnhanced.getRouteServiceEnhanced().getId());
        alerting.setUrl(routeServiceUrlEnhanced.getUrl());

        alerting = alertingDao.getOneByRecord(alerting);
        if (alerting != null) {
            alertingDao.deleteById(alerting.getId());//清除告警

            AlertNotice alertNotice = new AlertNotice();
            alertNotice.setAlertingId(alerting.getId());
            alertNotice.setStatus((int) StatusEnum4AlertNotice.EFFECTIVE.getCode());

            List<AlertNotice> alertNotices = alertNoticeDao.getListByRecord(alertNotice);
            if (Detect.notEmpty(alertNotices)) {
                alertNotices.forEach(e -> {
                    AlertNotice updateAlertNotice = new AlertNotice();
                    updateAlertNotice.setId(e.getId());
                    updateAlertNotice.setStatus((int) StatusEnum4AlertNotice.FINISH.getCode());
                    updateAlertNotice.setUpdateTime(new Date());

                    alertNoticeDao.updateByPrimaryKeySelective(updateAlertNotice);//关闭告警通知
                });
            }

            HealthCheckingErrorStatistics healthCheckingErrorStatistics = new HealthCheckingErrorStatistics();
            healthCheckingErrorStatistics.setApplicationName(routeServiceUrlEnhanced.getRouteServiceEnhanced().getApplicationName());
            healthCheckingErrorStatistics.setServiceId(routeServiceUrlEnhanced.getRouteServiceEnhanced().getId());
            healthCheckingErrorStatistics.setUrl(routeServiceUrlEnhanced.getUrl());

            healthCheckingErrorStatistics = healthCheckingErrorStatisticsDao.getOneByRecord(healthCheckingErrorStatistics);
            if (healthCheckingErrorStatistics != null) {
                HealthCheckingErrorStatistics updateHealthCheckingErrorStatistics = new HealthCheckingErrorStatistics();
                updateHealthCheckingErrorStatistics.setId(healthCheckingErrorStatistics.getId());
                updateHealthCheckingErrorStatistics.setUpdateTime(new Date());
                updateHealthCheckingErrorStatistics.setCount(0);

                healthCheckingErrorStatisticsDao.updateByPrimaryKeySelective(updateHealthCheckingErrorStatistics);//重置错误统计状态
            }
        }

        this.dealSendRecoveryNotice(routeServiceUrlEnhanced, applicationName);
    }

    private void dealSendRecoveryNotice(RouteServiceUrlEnhanced routeServiceUrlEnhanced, String applicationName) {
        AlertUserRouteService alertUserRouteServiceRecord = new AlertUserRouteService();
        alertUserRouteServiceRecord.setApplicationName(routeServiceUrlEnhanced.getRouteServiceEnhanced().getApplicationName());
        alertUserRouteServiceRecord.setServiceId(routeServiceUrlEnhanced.getRouteServiceEnhanced().getId());

        List<AlertUserRouteService> dbAlertUserRouteServices = alertUserRouteServiceDao.getListByRecord(alertUserRouteServiceRecord);
        if (!Detect.notEmpty(dbAlertUserRouteServices)) {
            return;
        }

        this.sendNotice(dbAlertUserRouteServices, routeServiceUrlEnhanced, applicationName);
    }

    private void sendNotice(List<AlertUserRouteService> dbAlertUserRouteServices, RouteServiceUrlEnhanced routeServiceUrlEnhanced, String applicationName) {
        String content = "【河姆渡】网关恢复:（ " + applicationName + "_" + env.get() + "网关 ）通知。服务组：（ " +
                routeServiceUrlEnhanced.getRouteServiceEnhanced().getId() + " ）,后端服务器（ " + routeServiceUrlEnhanced.getUrl() + " ）健康检查成功，服务已恢复上线。请知悉！";

        Map<String, String> headParamMap = Maps.newHashMap();
        headParamMap.put("h-x-app-name", DynamicPropertyFactory.getInstance().getStringProperty("spring.application.name", "").get());
        headParamMap.put("h-x-app-key", DynamicPropertyFactory.getInstance().getStringProperty("spring.application.key", "").get());
        headParamMap.put("h-x-app-version", DynamicPropertyFactory.getInstance().getStringProperty("_version", "1.0.0").get());

        dbAlertUserRouteServices.forEach(e -> {
            AlertUser alertUser = alertUserDao.getById(e.getAlterUserId());
            if (alertUser == null) {
                alertUser = new AlertUser();
            }
            try {
                String smsResponse = this.sendSms(alertUser.getPhoneNo(), content, headParamMap);
                ResponseData responseData = JSONObject.parseObject(smsResponse, ResponseData.class);
//                LOGGER.info("[服务恢复短信发送:{}--{}--{}--{}]", alertUser.getPhoneNo(), smsAddr.get(), headParamMap, smsResponse);
                if (!ResponseEnum.SUCCESSS.getCode().equals(responseData.getRespCode())) {
                    LOGGER.warn("[服务恢复短信发送异常:{}--{}--{}--{}]", alertUser.getPhoneNo(), smsAddr.get(), headParamMap, smsResponse);
                }
            } catch (Exception ex) {
                LOGGER.warn("[服务恢复短信发送异常:{}--{}--{}--{}]", alertUser.getPhoneNo(), smsAddr.get(), headParamMap, ex.getMessage());
            }

            try {
                String emailResponse = this.sendEmail(alertUser.getEmail(), content, headParamMap);
                ResponseData responseData = JSONObject.parseObject(emailResponse, ResponseData.class);
//                LOGGER.info("[服务恢复邮件发送:{}--{}--{}--{}]", alertUser.getEmail(), emailAddr.get(), headParamMap, emailResponse);
                if (!ResponseEnum.SUCCESSS.getCode().equals(responseData.getRespCode())) {
                    LOGGER.warn("[服务恢复邮件发送异常:{}--{}--{}--{}]", alertUser.getEmail(), emailAddr.get(), headParamMap, emailResponse);
                }
            } catch (Exception ex) {
                LOGGER.warn("[服务恢复邮件发送异常:{}--{}--{}--{}]", alertUser.getEmail(), emailAddr.get(), headParamMap, ex.getMessage());
            }

        });

    }


    private String sendEmail(String email, String content, Map<String, String> headParamMap) throws Exception {
        String emailUrl = emailAddr.get();
        Map<String, Object> emailRequestMap = Maps.newHashMap();
        Map<String, Object> emailBodyMap = Maps.newHashMap();

        emailBodyMap.put("attachmentUrl", "");
        emailBodyMap.put("content", content);
        emailBodyMap.put("cc", Lists.newArrayList());
        emailBodyMap.put("emails", Lists.newArrayList(email));
        emailBodyMap.put("fileBytes", "");
        emailBodyMap.put("fileName", "");
        emailBodyMap.put("kvMap", Maps.newHashMap());
        emailBodyMap.put("subject", "网关恢复通知");
        emailBodyMap.put("template", "");

        emailRequestMap.put("request", emailBodyMap);


        String emailJsonStr = JSONObject.toJSONString(emailRequestMap);

        return HttpUtility.httpPost(emailUrl, emailJsonStr, headParamMap);
    }

    private String sendSms(String phoneNo, String content, Map<String, String> headParamMap) throws Exception {
        String smsUrl = smsAddr.get();
        Map<String, Object> smsRequestMap = Maps.newHashMap();
        Map<String, Object> smsBodyMap = Maps.newHashMap();
        smsBodyMap.put("accountId", 0);
        smsBodyMap.put("content", content);
        smsBodyMap.put("desc", "");
        smsBodyMap.put("mobile", phoneNo);
        smsBodyMap.put("type", 0);

        smsRequestMap.put("request", smsBodyMap);

        String smsJsonStr = JSONObject.toJSONString(smsRequestMap);

        return HttpUtility.httpPost(smsUrl, smsJsonStr, headParamMap);
    }

    public boolean checkGet(String url) {
        HttpGet httpGet = null;
        CloseableHttpResponse httpresponse = null;
        CloseableHttpClient client = HttpClients.createDefault();
        try {
            httpGet = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(6000).setConnectTimeout(4000).build();
            // 设置超时
            httpGet.setConfig(requestConfig);

            httpresponse = client.execute(httpGet);

            int statusCode = httpresponse.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK == statusCode) {
                return true;
            }
            return false;
        } catch (Exception ex) {
            LOGGER.warn("[检测后端不健康服务,请求失败:{}--{}]", url, ex.getMessage());
            return false;
        } finally {
            if (httpresponse != null) {
                try {
                    httpresponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpGet != null && !httpGet.isAborted()) {
                httpGet.releaseConnection();
            }
            if (client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
